#include "../hdr/b64_decode.h"
#include <unistd.h>

#define ERR_WRITE 1
#define ERR_READ 2
#define ERR_INVALID_CHAR 3
#define ERR_INVALID_PAD 4
#define ERR_PADDING_NOT_EOF 5
#define ERR_EOF 6

/*const char* errmsg[] = {
	"No se pudo escribir en el archivo",
	"No se pudo leer del archivo",
	"Caracter inválido",
	"Padding inválido",
	"Padding antes de fin de archivo",
	"Fin de archivo inesperado"
};*/

/*	Registra los errores de decodificación en stream
	recibido por parámetro. */
void decode_log_error(FILE* error, int line, int byte, const char* msg)
{
	time_t rawtime;
	struct tm* timeinfo;

	time(&rawtime);
	timeinfo = localtime(&rawtime);

	fprintf(error, "%s\tError: línea %d, caracter %d: %s.\n", asctime(timeinfo),
			line, byte, msg);
}

/*	Dado un caracter codificado en base 64, devuelve su 
	equivalente en ASCII. En caso de no ser un caracter
	valido se devolvera -1. */
extern char base64_to_ascii(char c);
/*{
	if (c >= 'A' && c <= 'Z')
		return c - 'A';
	else if (c >= 'a' && c <= 'z')
		return c - 'a' + 26;
	else if (c >= '0' && c <= '9')
		return c - '0' + 52;
	else
		switch (c) 
		{
			case '+':
				return 62;
			case '/':
				return 63;
			case '=':
				return 0;
		}
	return -1;
}*/

extern int is_little_endian();
/*	Funcion que inverte el orden de los cuatro bytes del
	bloque recibido por parámetro. */

extern void invert_block_on_little_endian(char* block);
/*{
	char aux = block[3];
	if(!is_little_endian())
		return;
	block[3] = block[0];
	block[0] = aux;
	aux = block[2];
	block[2] = block[1];
	block[1] = aux;
}*/

/*int is_little_endian()
{
	int n = 0xff;
	char* p = (char*)&n;
	if(p[0] != 0)
		return 1;
	return 0;
}*/

extern void _decode_block_main(unsigned int* block, unsigned int* decoded_block);
/*{
	unsigned int filter = 0xfc000000;
	int i;
	for (i = 1; i <= 4; i++) {
		*decoded_block = *decoded_block | (filter & (*block << (2 * i)));
		filter = filter >> 6;
	}
}*/

extern void _decode_block_body(char* block, char* decoded_block);
/*{
	unsigned int *_block, *_decoded_block;
	char aux_block[4];
	int i;

	memset(decoded_block, 0, 4);

	_block = (unsigned int*) aux_block;
	_decoded_block = (unsigned int*) decoded_block;

	for(i = 0; i < 4; i++)
		aux_block[i] = base64_to_ascii(block[i]);
	
	invert_block_on_little_endian(aux_block);

	_decode_block_main(_block, _decoded_block);

	invert_block_on_little_endian(decoded_block);
}*/

/*	Dado un bloque de cuatro caracteres codificados en base 64, 
	decodifica el bloque, guardandolo en decoded_blocky devuelve
	la cantidad de bytes validos leidos. */
extern int decode_block(char* block, char* decoded_block);
/*{

	if (block[0] == '=')
		return -3;
	if (block[1] == '=')
		return -2;
	if ((block[2] == '=') && (block[3] != '=')) 
		return -1;

	_decode_block_body(block, decoded_block);

	if(block[2] == '=')
		return 1;
	if(block[3] == '=')
		return 2;
	return 3;
}*/

extern ssize_t my_read(int outfd, char* buffer, size_t nbytes);
/*{
	return read(outfd, buffer, nbytes);
}*/

extern ssize_t my_write(int outfd, char* buffer, size_t nbytes);
/*{
	return write(outfd, buffer, nbytes);
}*/

/*  Funcion principal para la decodificacion de archivos en 
	base 64. Se leera secuencialmente el contenido del archivo
	de entrada, agrupandose la informacion en bloques de
	cuatro bytes, se decodificaran los datos llamando a 
	decode_block y si estos son validos se guardaran en el 
	archivo de salida.  */
extern int base64_decode(int infd, int outfd);
/*{
	int i = 0, n = 3, line = 1, byte = 1, aux2;
	char block[4], decoded_block[4], aux;

	ssize_t nread;
	while(nread = my_read(infd, &(block[i]), sizeof(char))) 
	{
		if(nread == -1)
			return ERR_READ;
		if(block[i] == '\n')
		{
			line++;
			byte = 1;
		}
		else
		{
			aux = base64_to_ascii(block[i]);
			if(aux == -1)
			{
				return ERR_INVALID_CHAR;
			}
			if(n != 3)
			{
				return ERR_PADDING_NOT_EOF;
			}
			i++;
			byte++;
		}
	
		if(i == 4)
		{
			n = decode_block(block, decoded_block);
			if(n < 0)
			{
				return ERR_INVALID_PAD;
			}
			aux2 = my_write(outfd, decoded_block, sizeof(char) * n);
			if(aux2 != sizeof(char) * n)
				return ERR_WRITE;
			i = 0;
		}
	}

	if(i)
	{

		return ERR_EOF;
	}

	return RES_OK;
}*/
